#include "globalvar.h"
#define ISBLANK(x) x==' '||x=='\t'||x=='\n'||x=='\r'
#define EVALNEXT(x) np=0;sr=x.r;x=Eval(x);x.r=getNextPos(sr,&np);x.Q=a.Q;
#define WDGEVAL(ra,x) At tmp=getToken(ra);                   \
                    if(tmp.tag>ISRP)                         \
                    while(ra.tag!=ISRP)                      \
                  {                                          \
                    char  np=0;                              \
                    char* NextPos=getNextPos(ra.r,&np);      \
                    At NextAt=getToken({NextPos,NULL,ra.t,0,0});\
                    if(np==0&&NextAt.tag==ISRP){             \
                      return Eval(ra,wdg+1,wdgRP+x);         \
                    }                                        \
                    last=ra.tag;                             \
                    EVALNEXT(ra);                            \
                  }
#define WRITERP *(ra.w++)=')';*(ra.w++)=' ';
At func(At a,int wdg,int wdgRP)
{
  char* cmd=a.t,*sr,np;
  char last=ISNULL;

  At ra=a,parm;
  if(!strcmp(cmd,"echo"))
  {
    ra.tag=ISNULL;
    WDGEVAL(ra,0);
    
  }else if(!strcmp(cmd,"let"))
  {
    char*currRead=ra.r;
    while(true){
      currRead=ra.r;
      //获取TOKEN
      parm=getToken({ra.r,NULL,ra.t,0,0});
      if(parm.tag<ISTOKEN)break;
      //更新读取、暂存位置
      ra.r=parm.r;
      ra.t+=strlen(ra.t)+1;
      //获取值
      EVALNEXT(ra);
      parm.tag=ra.tag;
      //还原ra,以便之后求值
      ra.t=a.t;
      ra.w=a.w;
      if(ra.tag<ISLP)break;
      pushSymb(a.t,a.w);
    }
    ra.r=currRead;
    ra.tag=ISNULL;
    WDGEVAL(ra,0);
    
  }else if(!strcmp(cmd,"eval"))
  {
    last=ISNULL;
    char toWDG=0;
    do{
      At itoken=getToken(ra);
      //判别最后一项，可以尾递归
      if(itoken.tag>ISRP){
        char  np=0;                              
        char* NextPos=getNextPos(ra.r,&np);      
        At NextAt=getToken({NextPos,NULL,ra.t+strlen(ra.t)+1,0,0});
        if(np==0&&NextAt.tag==ISRP){             
          toWDG=1;         
        }
      }
      parm=ra;
      switch(itoken.tag){
      case ISNULL:
      case ISRP: goto OVER;
      //第一次求值该项
      case ISTOKEN:
        ra.r+=strlen(ra.r)+1;
        strcpy(ra.r,itoken.t);
        if(toWDG&&!itoken.Q)return Eval(ra,wdg+1,wdgRP);
        EVALNEXT(ra);
        parm.r=itoken.r;//保存读入结束位置
        break;
      case ISLP:
        ra.r =itoken.r-1;
        if(toWDG&&!itoken.Q)return Eval(ra,wdg+1,wdgRP);
        EVALNEXT(ra);
        parm.r=ra.r;    //保存读入结束位置
      }
      while(itoken.Q--){
        ra.w=parm.w;           //还原写出开始位置
        ra.r=a.r+strlen(a.r)+1;//结果拷贝到读取缓存区
        strcpy(ra.r,parm.w);
        //第二次求值该项
        if(toWDG&&!itoken.Q)return Eval(ra,wdg+1,wdgRP);
        EVALNEXT(ra);
      }     
      last=ra.tag;
      parm.w=ra.w;
      ra=parm;                 //还原读入结束位置
      ra.Q=a.Q;
    }while(true);
    
  }else if(!strcmp(cmd,"quot"))
  {
    last=ISNULL;
    do{
      At itoken=getToken(ra);
      parm=ra;
      switch(itoken.tag){
      case ISNULL:
      case ISRP: goto OVER;
      case ISTOKEN:
        ra.r+=strlen(ra.r)+1;
        strcpy(ra.r,itoken.t);
        EVALNEXT(ra);
        parm.r=itoken.r;
        break;
      case ISLP:
        ra.r =itoken.r-1;
        EVALNEXT(ra);
        parm.r=ra.r;
      }
      parm.tag=last=ra.tag;
      parm.Q +=itoken.Q+1;
      ra=parm;
      ra.r   +=strlen(ra.r)+1;
      strcpy(ra.r,parm.w);
      EVALNEXT(ra);
      last=ra.tag;
      parm.w=ra.w;
      ra=parm;
      ra.Q=a.Q;
    }while(true);

  }else if(!strcmp(cmd,"if"))
  {
    last=ISNULL;
    ra.tag=ISNULL;
    //求值条件表达式
    EVALNEXT(ra);
    ra.w=a.w;
    //判断if体内容是否存在
    parm=getToken({ra.r,NULL,ra.t,0,0});
    if(ra.tag!=ISRP&&np==0&&parm.tag!=ISRP&&parm.tag!=ISNULL)
    {//判断真：非空或无限次求值为空、假：空或有限次求值为空
      parm=getToken({a.w,NULL,a.t,0,0});
      if(!parm.tag)
      {//假，越过真体，求值后面所有
        ra.r=getNextPos(ra.r);
        WDGEVAL(ra,0);
      }else
      {//真，尾递归真体
        return Eval(ra,wdg+1,wdgRP);
      }
    }
   
  }else if(!strcmp(cmd,"="))
  {
    //求值第一项
    EVALNEXT(ra);
    parm=ra;
    if(ra.tag!=ISRP)
    {    
      while(true)
      {//求值其他项
        last=ra.tag;
        ra.w=parm.w+1;
        EVALNEXT(ra);
        if(ra.tag<=ISRP)
        {//遇到空或）
          ra.w=parm.w;
          break;
        }

        if(strcmp(parm.w+1,a.w))
        {//与第一项不等
          last=ISTOKEN;
          ra.w=a.w;
          break;
        }
      }
    }else
    {//第一项为）
      last=ISNULL;
    }

  }else if(!strcmp(cmd,"and"))
  {
    ra.tag=ISNULL;
    WDGEVAL(ra,0);
    
  }else if(!strcmp(cmd,"or"))
  {
    ra.tag=ISNULL;
    WDGEVAL(ra,0);
    
  }else if(!strcmp(cmd,"not"))
  {
    ra.tag=ISNULL;
    WDGEVAL(ra,0);
    
  }else if(!strcmp(cmd,"car"))
  {
    last=ISNULL; 
    while(true){
      parm=ra;
      ra=Eval(ra);
      if(ra.tag<=ISRP)break;
      At tmp=getToken({parm.w,NULL,parm.t,0,0});
      if(tmp.tag==ISLP){
        np=0;
        char* startAt=tmp.r;
        char* endAt=getNextPos(startAt,&np);
        if(np==0){
          int i,n=endAt-startAt;
          for(i=0;i<n;++i)
            parm.w[i]=startAt[i];
          parm.w[i++]=' ';parm.w[i++]='\0';
          tmp=getToken({parm.w,NULL,a.t,0,0});
          last=tmp.tag;
        }else{
          goto CARFAIL;
        }
      }else{
        CARFAIL:
        *parm.w='\0';
      }
      ra.w=parm.w+strlen(parm.w);
      ra.r=getNextPos(parm.r,&np);
      ra.Q=a.Q;
    }
    
  }else if(!strcmp(cmd,"cdr"))
  {
    last=ISNULL; 
    while(true){
      parm=ra;
      ra=Eval(ra);
      if(ra.tag<=ISRP)break;
      At tmp=getToken({parm.w,NULL,parm.t,0,0});
      if(tmp.tag==ISLP){
        np=0;
        char* startAt = getNextPos(tmp.r,&np);
        char* endAt   = ra.w;

        while(ISBLANK(*startAt))++startAt;
	if(np==0){
          *(parm.w++)='(';
          last=ISLP;
          int i,n=endAt-startAt;
          for(i=0;i<n;++i)
            parm.w[i]=startAt[i];
          parm.w[i++]='\0';
	}else{
          goto CDRFAIL;
        }
      }else{
        CDRFAIL:     
        *parm.w='\0';
      }
      ra.w=parm.w+strlen(parm.w);
      ra.r=getNextPos(parm.r,&np);
      ra.Q=a.Q;
    }   

  }else if(!strcmp(cmd,"sh"))
  {
    ra.tag=ISNULL;
    ra.w=a.t;
    ra.t=a.w;
    do{
      EVALNEXT(ra);
    }while(ra.tag!=ISRP);
    shell(a.t,a.w,&ra.w);
    parm=getToken({a.w,NULL,a.t,0,0});
    last=parm.tag;
    
  }else{
    ra.w+=strlen(ra.w);
    ra.tag=ISTOKEN;
    WDGEVAL(ra,1);
    WRITERP
  }
OVER:
  popTable();
  while(wdgRP--){WRITERP}
  *(ra.w)='\0';
  return {a.r,ra.w,a.t,a.Q,last};
}
